﻿#include "uptrianglewindow.h"
#include <QDebug>
#include <QImage>

static const char *vertexShaderSource =
    "attribute highp vec3 posAttr;\n"
    "attribute lowp vec3 colAttr;\n"
    "varying lowp vec3 col;\n"
    "uniform lowp vec3 aNormal;\n"
    "uniform highp mat4 projection;\n"
    "uniform highp mat4 view;\n"
    "uniform highp mat4 model;\n"
    "attribute vec2 a_texcoord;\n"

    "varying highp vec2 v_texcoord;\n"
    "varying vec3 Normal;\n"
    "varying vec3 FragPos;\n"

    "void main() {\n"
    "   gl_Position = projection * view * model * vec4(posAttr, 1.0);\n"
    "   gl_PointSize = 10.0;\n"
    "   FragPos = vec3(model * vec4(posAttr, 1.0));\n"
    "   v_texcoord = a_texcoord;\n"
//    "   Normal = mat3(transpose(inverse(model))) * aNormal;\n"
    "   col = colAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "varying lowp vec3 col;\n"
    "uniform sampler2D texture;\n"
    "uniform lowp vec3 ambientColAttr;\n"
    "uniform lowp vec3 lightColAttr;\n"
    "uniform lowp vec3 lightPosAttr;\n"
    "uniform lowp vec3 viewPosAttr;\n"

    "varying highp vec2 v_texcoord;\n"
    "varying vec3 Normal;\n"
    "varying vec3 FragPos;\n"

    "void main() {\n"
    //漫反射
//    "   vec3 norm = normalize(Normal);\n"
//    "   vec3 lightDir = normalize(lightPosAttr - FragPos);\n"
//    "   float ambientStrength = 0.5;\n"
//    "   float diffuse = max(dot(norm, lightDir), 0.0);\n"

    //高光
//    "   vec3 viewDir = normalize(viewPosAttr - FragPos);\n"
//    "   vec3 reflecDir = reflect(-lightDir, norm);\n"
//    "   float specularStrength = 0.5;\n"
//    "   float specular = pow(max(dot(viewDir, reflecDir), 0.0), 64) * specularStrength;\n"
    "   gl_FragColor = vec4(col, 1.0) * texture2D(texture, v_texcoord);\n"
    "}\n";
//vec4(1.0f, 1.0f, 0.0f, 1.0f)
//texture2D(texture, v_texcoord)

struct VertexData1
{
    QVector3D position;
    QVector2D color;
};

struct VertexData
{
    QVector3D position;
    QVector3D color;
    QVector3D texture;
};

UpTriangleWindow::UpTriangleWindow()
    :m_program(0)
    ,m_frame(0)
{

}

UpTriangleWindow::~UpTriangleWindow()
{
    delete m_program;
}

void UpTriangleWindow::initialize()
{
//    //背景色
//    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    //启用2D纹理映射
    glEnable(GL_TEXTURE_2D);
    //启用混合
    glEnable(GL_BLEND);

    //设置混合参数
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //创建着色器程序
    m_program = new QOpenGLShaderProgram(this);
    //编译代码-添加顶点着色器
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    //编译代码-添加片段着色器
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);

    //链接着色器
    m_program->link();

    //得到顶点属性名在着色器参数列表中的位置-0
    m_posAttr = m_program->attributeLocation("posAttr");
    //得到颜色属性名在着色器参数列表中的位置-1
    m_colAttr = m_program->attributeLocation("colAttr");
    //得到矩阵规格名在着色器参数列表中的位置-0
    m_projection = m_program->uniformLocation("projection");
    m_view = m_program->uniformLocation("view");
    m_model = m_program->uniformLocation("model");
    //环境光属性
    m_ambientColAttr = m_program->uniformLocation("ambientColAttr");
    //点光源属性
    m_lightColAttr = m_program->uniformLocation("lightColAttr");
    m_lightPosAttr = m_program->uniformLocation("lightPosAttr");
    m_aNormal = m_program->uniformLocation("aNormal");
    //视点属性
    m_viewPosAttr = m_program->uniformLocation("viewPosAttr");

    //得到纹理属性名在着色器参数列表中的位置-2
    m_texcoordLocation = m_program->attributeLocation("a_texcoord");

    //VAO数据，顶点与颜色
    QVector3D vcs[] = {
        //正面
        QVector3D(-0.5f, 0.0f, 0.5f),
        QVector3D(0.5f, 0.0f, 0.5f),
        QVector3D(0.5f, 1.0f, 0.5f),
        QVector3D(-0.5f, 1.0f, 0.5f),

        QVector3D(0.5f, 0.0f, -0.5f),
        QVector3D(0.5f, 1.0f, -0.5f),
        QVector3D(-0.5f, 1.0f, -0.5f),
        QVector3D(-0.5f, 0.0f, -0.5f),
    };

    VertexData textCoodBg[] = {
        {QVector3D(-0.5f, -0.5f, 0.0f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 0.0f)},     //1
        {QVector3D(0.5f, -0.5f, 0.0f),  QVector3D(1.0f, 1.0f, 1.0f), QVector2D(1.0f, 0.0f)},      //2
        {QVector3D(0.5f, 0.5f, 0.0f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},      //3
        {QVector3D(-0.5f, 0.5f, 0.0f),QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //4
    };

    VertexData vc[] = {
        //正面
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector3D(1.0f, 0.0f, 0.0f), QVector2D(0.0f, 0.0f)},     //1
        {QVector3D(-0.5f, 1.0f, 0.5f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //4
        {QVector3D(0.5f, 0.0f, 0.5f),  QVector3D(0.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},      //2

        {QVector3D(-0.5f, 1.0f, 0.5f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //4
        {QVector3D(0.5f, 0.0f, 0.5f),  QVector3D(0.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},      //2
        {QVector3D(0.5f, 1.0f, 0.5f),  QVector3D(0.0f, 0.0f, 1.0f), QVector2D(1.0f, 1.0f)},      //3


        //右面
        {QVector3D(0.5f, 0.0f, 0.5f),  QVector3D(0.0f, 1.0f, 0.0f), QVector2D(0.0f, 0.0f)},     //2
        {QVector3D(0.5f, 1.0f, 0.5f),  QVector3D(0.0f, 0.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //3
        {QVector3D(0.5f, 0.0f, -0.5f), QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //5

        {QVector3D(0.5f, 1.0f, 0.5f),  QVector3D(0.0f, 0.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //3
        {QVector3D(0.5f, 0.0f, -0.5f), QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //5
        {QVector3D(0.5f, 1.0f, -0.5f), QVector3D(0.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},     //6

        //左面
        {QVector3D(-0.5f, 0.0f, -0.5f),QVector3D(1.0f, 0.0f, 1.0f), QVector2D(0.0f, 0.0f)},     //8
        {QVector3D(-0.5f, 1.0f, -0.5f),QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},     //7
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector3D(1.0f, 0.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //1

        {QVector3D(-0.5f, 1.0f, -0.5f),QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},     //7
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector3D(1.0f, 0.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //1
        {QVector3D(-0.5f, 1.0f, 0.5f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},     //4


        //背面
        {QVector3D(0.5f, 0.0f, -0.5f),   QVector3D(1.0f, 1.0f, 0.0f), QVector2D(0.0f, 0.0f)},   //5
        {QVector3D(0.5f, 1.0f, -0.5f),   QVector3D(0.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},   //6
        {QVector3D(-0.5f, 0.0f, -0.5f),  QVector3D(1.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //8

        {QVector3D(0.5f, 1.0f, -0.5f),   QVector3D(0.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},   //6
        {QVector3D(-0.5f, 0.0f, -0.5f),  QVector3D(1.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //8
        {QVector3D(-0.5f, 1.0f, -0.5f),  QVector3D(1.0f, 0.6f, 0.0f), QVector2D(1.0f, 1.0f)},   //7


        //顶面
        {QVector3D(-0.5f, 1.0f, 0.5f),   QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 0.0f)},   //4
        {QVector3D(-0.5f, 1.0f, -0.5f),  QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},   //7
        {QVector3D(0.5f, 1.0f, 0.5f),    QVector3D(0.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //3

        {QVector3D(-0.5f, 1.0f, -0.5f),  QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},   //7
        {QVector3D(0.5f, 1.0f, 0.5f),    QVector3D(0.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //3
        {QVector3D(0.5f, 1.0f, -0.5f),   QVector3D(0.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},   //6


        //底面
        {QVector3D(-0.5f, 0.0f, -0.5f),  QVector3D(1.0f, 0.0f, 1.0f), QVector2D(0.0f, 0.0f)},   //8
        {QVector3D(-0.5f, 0.0f, 0.5f),   QVector3D(1.0f, 0.0f, 0.0f), QVector2D(0.0f, 1.0f)},   //1
        {QVector3D(0.5f, 0.0f, -0.5f),   QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},   //5

        {QVector3D(-0.5f, 0.0f, 0.5f),   QVector3D(1.0f, 0.0f, 0.0f), QVector2D(0.0f, 1.0f)},   //1
        {QVector3D(0.5f, 0.0f, -0.5f),   QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},   //5
        {QVector3D(0.5f, 0.0f, 0.5f),    QVector3D(0.0f, 1.0f, 0.0f), QVector2D(1.0f, 1.0f)},   //2

    };

    //索引
    GLuint indices[] = { // 起始于0!
        0, 1, 2, 3,// face 1
        1, 4, 5, 2,  // face 2
        0, 7, 6, 3,  // face 3
        4, 5, 6, 7,  // face 4
        2, 5, 6, 3,  // face 5
        1, 4, 7, 0,  // face 6
    };

    //1 使用glGenBuffers函数生成一个缓冲ID    
    glGenVertexArrays(2, m_VAO);
    glGenBuffers(2, m_VBO);
    glGenBuffers(2, m_EBO);
    //2 绑定vao
    glBindVertexArray(m_VAO[0]);
    //3 使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER缓冲类型上
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO[0]); //（绑定和解绑的顺序很重要，勿更改）
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO[0]);
    //4 把用户定的义数据复制到当前绑定缓冲的函数
    glBufferData(GL_ARRAY_BUFFER, sizeof(vc), vc, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(m_posAttr);
    glEnableVertexAttribArray(m_colAttr);
    glEnableVertexAttribArray(m_texcoordLocation);

    //5 链接顶点属性
    //indx: 属性名
    //size: 顶点大小
    //type: 数据类型
    //normalized：数据被标准化
    //stride: 步长
    //ptr: 数据在缓冲中起始位置的偏移量
    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)0);    //(GLvoid*)0
    glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*1));
    glVertexAttribPointer(m_texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*2));

    glBindVertexArray(m_VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO[1]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO[1]);

    glBufferData(GL_ARRAY_BUFFER, sizeof(textCoodBg), textCoodBg, GL_STATIC_DRAW);

    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)0);
    glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*1));
    glVertexAttribPointer(m_texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*2));

    //6 解绑缓存着色器（绑定和解绑的顺序很重要，勿更改）
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //7 解绑VAO
    glBindVertexArray(0);

    for(int i=0; i<6; i++)
    {
        //使用图片的垂直镜像来创建纹理
        QString path = QString(":/img/img/cube%1.png").arg(QString::number(i+1));
        QOpenGLTexture *_texture = new QOpenGLTexture(QImage(path).mirrored());
        //设置纹理过滤器的滤波方式
        //当图片缩小的比原始纹理小的时候 滤波方式为 mip层之间使用线性插值和使用线性过滤
        _texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
        //当图片放大的比原始纹理大的时候 滤波方式为 mip基层上使用线性过滤
        _texture->setMagnificationFilter(QOpenGLTexture::Linear);

        m_vTexture.append(_texture);
    }

    //背景
    m_textureBg = new QOpenGLTexture(QImage(":/img/img/startBg.png").mirrored());
    m_textureBg->setMinificationFilter(QOpenGLTexture::Linear);
    m_textureBg->setMagnificationFilter(QOpenGLTexture::Linear);

    //使用纹理单元
    m_program->setUniformValue("texture", 0);

}

void UpTriangleWindow::render()
{
    //背景色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    //重置视口
    glViewport(0, 0, getViewportSize().width(), getViewportSize().height());

    //清除颜色缓冲区
//    glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);

    //启用混合
    glEnable(GL_BLEND);

    //设置混合参数
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //绑定着色器程序到活动的上下文
    m_program->bind();

//    //描绘背景
//    glBindVertexArray(m_VAO[1]);
//    glBindBuffer(GL_ARRAY_BUFFER, m_VBO[1]);

//    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)0);
//    glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*1));
//    glVertexAttribPointer(m_texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*2));

//    //背景的矩阵
//    QMatrix4x4 modelBg;
//    modelBg.translate(0.0f, 0.0f, -10.0f);
//    modelBg.scale(4.0f * 8, 3.0f * 8, 1.0f);
//    modelBg.rotate(0, 0, 1, 0);
//    m_program->setUniformValue(m_model, modelBg);

//    glBlendFunc(GL_ZERO, GL_ZERO);

//    m_textureBg->bind();

//    glDrawArrays(GL_QUADS,0, 4);
//    m_textureBg->release();

    //设置混合参数
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    //4x4 矩阵
    QMatrix4x4 projection, view, model;
    //乘以一个矩阵，为了建立透视投影矩阵
    projection.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f);
    //乘以这个矩阵，通过向量转换坐标
    GLfloat camX = sin((GLfloat)m_frame/100) * 3.0f;
    GLfloat camZ = cos((GLfloat)m_frame/100) * 3.0f;
    QVector3D camera = QVector3D(0, 0.0f, 10.0f);
    view.lookAt(camera, QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f));
    //乘以这个矩阵，通过向量上的角度旋转坐标
    model.translate(1.0f, 0.0f, 7.0f);
    model.scale(0.5f, 0.5f, 0.5f);
    model.rotate(m_frame, 0, 1, 0);

    //设置矩阵数据
    m_program->setUniformValue(m_projection, projection);
    m_program->setUniformValue(m_view, view);
    m_program->setUniformValue(m_model, model);

    //环境光
    QVector3D ambient(1.0f, 1.0f, 1.0f);
    m_program->setUniformValue(m_ambientColAttr, ambient);

    //点光源-漫反射
    QVector3D pointLightCol(1.0f, 1.0f, 1.0f);
    m_program->setUniformValue(m_lightColAttr, pointLightCol);

    QVector3D pointLightPos(0.0f, 1.0f, 0.0f);
    m_program->setUniformValue(m_lightPosAttr, pointLightPos);

    //法线=强度
    QVector3D objNormal(0.0f, 1.0f, 0.0f);
    m_program->setUniformValue(m_aNormal, objNormal);

    //视点为摄像机位置
    m_program->setUniformValue(m_viewPosAttr, camera);

    //2 开启顶点属性
    glEnableVertexAttribArray(m_posAttr);
    //颜色值
    glEnableVertexAttribArray(m_colAttr);
    //纹理
    glEnableVertexAttribArray(m_texcoordLocation);

    //1 绑定vaoshi
    glBindVertexArray(m_VAO[0]);

    //纹理绑定
    for(int i=0; i<6; i++)
    {
        m_vTexture.at(i)->bind();
        //3 绘制四边形
        //24个索引值
        glDrawArrays(GL_TRIANGLES, i*6, 6);
//          glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, (GLvoid*)(indices));

        m_vTexture.at(i)->release();
    }

    //4 停用对应的顶点属性数组
    glDisableVertexAttribArray(m_texcoordLocation);
    glDisableVertexAttribArray(m_colAttr);
    glDisableVertexAttribArray(m_posAttr);

    //5 解绑VAO
//    glBindVertexArray(0);

    //释放程序
    m_program->release();

//    m_frame++;

}
